import qs from "qs";
import bencode from "bencode";
import User from "../schema/user";
import Torrent from "../schema/torrent";
import Progress from "../schema/progress";
import Peer from "../schema/peer"; // 新增：Peer 模型
import { getUserRatio } from "../utils/ratio";
import { getUserHitNRuns } from "../utils/hitnrun";

export const BYTES_GB = 1e9;

export const binaryToHex = (b) => Buffer.from(b, "binary").toString("hex");
export const hexToBinary = (h) => Buffer.from(h, "hex").toString("binary");

// 辅助函数：格式化字节数
const formatBytes = (bytes) => {
  if (bytes === 0) return "0 Bytes";
  const k = 1024;
  const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
};

// 辅助函数：获取客户端信息
const getClientInfo = (peerId) => {
  if (!peerId) return "Unknown Client";

  // 常见BitTorrent客户端的peer_id前缀
  const clientPrefixes = {
    "-AZ": "Azureus",
    "-UT": "μTorrent",
    "-TR": "Transmission",
    "-qB": "qBittorrent",
    "-DE": "Deluge",
    "-LT": "libtorrent",
    "-RT": "rTorrent",
    "-TT": "TorrentTornado",
  };

  for (const [prefix, client] of Object.entries(clientPrefixes)) {
    if (peerId.startsWith(prefix)) {
      return client;
    }
  }

  return "Unknown Client";
};

// 新增：清理过期的 peers
const cleanExpiredPeers = async (infoHash) => {
  const expireTime = new Date(Date.now() - 60 * 60 * 1000); // 1小时前
  await Peer.deleteMany({
    infoHash,
    lastAnnounce: { $lt: expireTime },
  });
};

// 修改：将 IPv4 地址转换为 4 字节的 Buffer（支持 IPv6-mapped IPv4）
const ipToBuffer = (ip) => {
  // 处理 IPv6 映射的 IPv4 地址（如 ::ffff:192.168.220.13）
  if (ip.startsWith("::ffff:")) {
    ip = ip.substring(7); // 移除 ::ffff: 前缀
  }

  const parts = ip.split(".");
  if (parts.length !== 4) {
    throw new Error(`Invalid IPv4 address: ${ip}`);
  }

  return Buffer.from(
    parts.map((part) => {
      const num = parseInt(part, 10);
      if (isNaN(num) || num < 0 || num > 255) {
        throw new Error(`Invalid IPv4 address part: ${part}`);
      }
      return num;
    })
  );
};

// 新增：将端口转换为 2 字节的 Buffer（big-endian）
const portToBuffer = (port) => {
  const buffer = Buffer.allocUnsafe(2);
  buffer.writeUInt16BE(parseInt(port, 10), 0);
  return buffer;
};

// 修改：构建 compact peer 列表（增强错误处理和调试）
const buildCompactPeers = (peers) => {
  if (peers.length === 0) {
    return Buffer.alloc(0);
  }

  console.log("\n---------- COMPACT PEER LIST DEBUG ----------");

  const peerBuffers = peers
    .map((peer, index) => {
      try {
        // 确保 IP 是纯 IPv4 格式
        let peerIp = peer.ip;
        if (peerIp.startsWith("::ffff:")) {
          peerIp = peerIp.substring(7);
        }

        const ipBuffer = ipToBuffer(peerIp);
        const portBuffer = portToBuffer(peer.port);

        console.log(
          `[DEBUG] Peer ${index + 1}: ${peer.ip} -> ${peerIp}:${peer.port} (${
            peer.username
          })`
        );

        return Buffer.concat([ipBuffer, portBuffer]);
      } catch (error) {
        console.log(
          `[DEBUG] ⚠️  Invalid peer address: ${peer.ip}:${peer.port}, error: ${error.message}`
        );
        return null;
      }
    })
    .filter((buffer) => buffer !== null);

  // 打印最终的 compact peer list 内容
  if (peerBuffers.length > 0) {
    const finalBuffer = Buffer.concat(peerBuffers);
    console.log("[DEBUG] Compact peer list hex:", finalBuffer.toString("hex"));

    // 解析并验证 compact peer list
    for (let i = 0; i < finalBuffer.length; i += 6) {
      const ip = `${finalBuffer[i]}.${finalBuffer[i + 1]}.${
        finalBuffer[i + 2]
      }.${finalBuffer[i + 3]}`;
      const port = (finalBuffer[i + 4] << 8) | finalBuffer[i + 5];
      console.log(`[DEBUG] Encoded peer ${i / 6 + 1}: ${ip}:${port}`);
    }
  }

  return Buffer.concat(peerBuffers);
};

// 新增：构建标准 peer 列表
const buildStandardPeers = (peers) => {
  return peers.map((peer) => {
    // 确保 IP 是纯 IPv4 格式
    let peerIp = peer.ip;
    if (peerIp.startsWith("::ffff:")) {
      peerIp = peerIp.substring(7);
    }

    return {
      "peer id": hexToBinary(peer.peerId),
      ip: peerIp,
      port: peer.port,
    };
  });
};

// 修改：获取真实客户端 IP（返回纯 IPv4 格式）
const getClientIP = (req, params) => {
  let ip;

  // 优先使用 announce 参数中的 IP
  if (params.ip && params.ip !== "0.0.0.0") {
    ip = params.ip;
  } else {
    // 检查常见的代理头
    const forwardedFor = req.headers["x-forwarded-for"];
    if (forwardedFor) {
      const ips = forwardedFor.split(",").map((ip) => ip.trim());
      ip = ips[0];
    } else {
      const realIP = req.headers["x-real-ip"];
      if (realIP) {
        ip = realIP;
      } else {
        // 最后使用连接 IP
        ip = req.ip || req.connection.remoteAddress || req.socket.remoteAddress;
      }
    }
  }

  // 处理 IPv6 映射的 IPv4 地址，返回纯 IPv4 格式
  if (ip && ip.startsWith("::ffff:")) {
    ip = ip.substring(7);
  }

  return ip;
};

const handleAnnounce = async (req, res) => {
  const userId = req.originalUrl.split("/")[2];
  req.userId = userId;

  console.log("\n========== ANNOUNCE REQUEST DEBUG INFO ==========");
  console.log(`[DEBUG] Timestamp: ${new Date().toISOString()}`);
  console.log(`[DEBUG] userId: ${userId}`);
  console.log(`[DEBUG] Request IP: ${req.ip || req.connection.remoteAddress}`);
  console.log(`[DEBUG] User-Agent: ${req.headers["user-agent"]}`);

  const user = await User.findOne({ uid: userId }).lean();

  // if the uid does not match a registered user, deny announce
  if (!user) {
    console.log(`[DEBUG] ❌ User not found for uid: ${userId}`);
    const response = bencode.encode({
      "failure reason": "Announce denied: you are not registered.",
    });
    res.send(response);
    return;
  }

  console.log(`[DEBUG] ✅ User found: ${user.username} (${user.email})`);

  // if the users email is not verified, deny announce
  if (!user.emailVerified) {
    console.log(`[DEBUG] ❌ User email not verified: ${user.email}`);
    const response = bencode.encode({
      "failure reason": "Announce denied: email address must be verified.",
    });
    res.send(response);
    return;
  }

  const q = req.url.split("?")[1];
  const params = qs.parse(q, { decoder: unescape });

  const infoHash = binaryToHex(params.info_hash);
  const peerId = params.peer_id ? binaryToHex(params.peer_id) : null;
  const clientIP = getClientIP(req, params); // 现在返回纯 IPv4 格式

  console.log("\n---------- ANNOUNCE PARAMETERS ----------");
  console.log(`[DEBUG] Info Hash: ${infoHash}`);
  console.log(`[DEBUG] Peer ID: ${peerId}`);
  console.log(`[DEBUG] Client: ${getClientInfo(params.peer_id)}`);
  console.log(
    `[DEBUG] IP: ${clientIP} (cleaned from ${
      req.ip || req.connection.remoteAddress
    })`
  );
  console.log(`[DEBUG] Port: ${params.port}`);
  console.log(
    `[DEBUG] Uploaded: ${formatBytes(Number(params.uploaded))} (${
      params.uploaded
    } bytes)`
  );
  console.log(
    `[DEBUG] Downloaded: ${formatBytes(Number(params.downloaded))} (${
      params.downloaded
    } bytes)`
  );
  console.log(
    `[DEBUG] Left: ${formatBytes(Number(params.left))} (${params.left} bytes)`
  );
  console.log(`[DEBUG] Event: ${params.event || "none"}`);
  console.log(`[DEBUG] Numwant: ${params.numwant || 50}`);
  console.log(`[DEBUG] Compact: ${params.compact}`);

  const torrent = await Torrent.findOne({ infoHash }).lean();

  // if torrent info hash is not in the database, deny announce
  if (!torrent) {
    console.log(`[DEBUG] ❌ Torrent not found for infoHash: ${infoHash}`);
    const response = bencode.encode({
      "failure reason":
        "Announce denied: cannot announce a torrent that has not been uploaded.",
    });
    res.send(response);
    return;
  }

  console.log("\n---------- TORRENT INFO ----------");
  console.log(`[DEBUG] ✅ Torrent found: ${torrent.name}`);
  console.log(`[DEBUG] Torrent size: ${formatBytes(torrent.size)}`);
  console.log(`[DEBUG] Freeleech: ${torrent.freeleech}`);
  console.log(`[DEBUG] Downloads: ${torrent.downloads}`);
  console.log(
    `[DEBUG] Site-wide freeleech: ${process.env.SQ_SITE_WIDE_FREELEECH}`
  );

  const { ratio } = await getUserRatio(user._id);
  const hitnruns = await getUserHitNRuns(user._id);

  console.log("\n---------- USER STATS ----------");
  console.log(
    `[DEBUG] User ratio: ${
      ratio === -1 ? "Infinite (no downloads)" : ratio.toFixed(3)
    }`
  );
  console.log(`[DEBUG] User hit'n'runs: ${hitnruns}`);
  console.log(`[DEBUG] User bonus points: ${user.bonusPoints || 0}`);
  console.log(
    `[DEBUG] Minimum ratio requirement: ${process.env.SQ_MINIMUM_RATIO}`
  );
  console.log(
    `[DEBUG] Maximum hit'n'runs allowed: ${process.env.SQ_MAXIMUM_HIT_N_RUNS}`
  );

  // if users ratio is below the minimum threshold, and they are trying to download, deny announce
  // if (
  //   Number(process.env.SQ_MINIMUM_RATIO) !== -1 &&
  //   ratio < Number(process.env.SQ_MINIMUM_RATIO) &&
  //   ratio !== -1 &&
  //   Number(params.left > 0)
  // ) {
  //   console.log(`[DEBUG] ❌ Ratio check failed: ${ratio} < ${process.env.SQ_MINIMUM_RATIO}`);
  //   const response = bencode.encode({
  //     "failure reason": `Announce denied: Ratio is below minimum threshold ${process.env.SQ_MINIMUM_RATIO}.`,
  //     peers: [],
  //     peers6: [],
  //   });
  //   res.send(response);
  //   return;
  // }

  // // if user has committed more than the allowed number of hit'n'runs, and they are trying to download, deny announce
  // if (
  //   Number(process.env.SQ_MAXIMUM_HIT_N_RUNS) !== -1 &&
  //   hitnruns >= Number(process.env.SQ_MAXIMUM_HIT_N_RUNS) &&
  //   Number(params.left > 0)
  // ) {
  //   console.log(`[DEBUG] ❌ Hit'n'run check failed: ${hitnruns} >= ${process.env.SQ_MAXIMUM_HIT_N_RUNS}`);
  //   const response = bencode.encode({
  //     "failure reason": `Announce denied: You have committed ${process.env.SQ_MAXIMUM_HIT_N_RUNS} or more hit'n'runs.`,
  //     peers: [],
  //     peers6: [],
  //   });
  //   res.send(response);
  //   return;
  // }

  const uploaded = Number(params.uploaded);
  const downloaded = params.event === "started" ? 0 : Number(params.downloaded);

  const prevProgressRecord = await Progress.findOne({
    userId: user._id,
    infoHash,
  }).lean();

  console.log("\n---------- PROGRESS UPDATE ----------");
  if (prevProgressRecord) {
    console.log(`[DEBUG] Previous progress record found:`);
    console.log(
      `  - Total uploaded: ${formatBytes(
        prevProgressRecord.uploaded?.total || 0
      )}`
    );
    console.log(
      `  - Total downloaded: ${formatBytes(
        prevProgressRecord.downloaded?.total || 0
      )}`
    );
    console.log(
      `  - Session uploaded: ${formatBytes(
        prevProgressRecord.uploaded?.session || 0
      )}`
    );
    console.log(
      `  - Session downloaded: ${formatBytes(
        prevProgressRecord.downloaded?.session || 0
      )}`
    );
    console.log(`  - Left: ${formatBytes(prevProgressRecord.left || 0)}`);
  } else {
    console.log(`[DEBUG] No previous progress record - this is a new announce`);
  }

  const alreadyUploadedSession = prevProgressRecord?.uploaded?.session ?? 0;
  const uploadDeltaSession =
    uploaded >= alreadyUploadedSession ? uploaded - alreadyUploadedSession : 0;

  const alreadyDownloadedSession = prevProgressRecord?.downloaded?.session ?? 0;
  const downloadDeltaSession =
    downloaded >= alreadyDownloadedSession
      ? downloaded - alreadyDownloadedSession
      : 0;

  console.log(
    `[DEBUG] Upload delta this announce: ${formatBytes(uploadDeltaSession)}`
  );
  console.log(
    `[DEBUG] Download delta this announce: ${formatBytes(downloadDeltaSession)}`
  );

  const [sumUploaded] = await Progress.aggregate([
    {
      $match: {
        userId: user._id,
      },
    },
    {
      $group: {
        _id: "uploaded",
        bytes: { $sum: "$uploaded.total" },
      },
    },
  ]);

  const { bytes } = sumUploaded ?? { bytes: 0 };
  const nextGb = Math.max(Math.ceil((bytes + 1) / BYTES_GB), 1);
  const currentGb = nextGb - 1;

  const gbAfterUpload = Math.floor((bytes + uploadDeltaSession) / BYTES_GB);

  console.log("\n---------- BONUS POINTS CALCULATION ----------");
  console.log(
    `[DEBUG] Total uploaded across all torrents: ${formatBytes(bytes)}`
  );
  console.log(`[DEBUG] Current GB milestone: ${currentGb} GB`);
  console.log(`[DEBUG] Next GB milestone: ${nextGb} GB`);
  console.log(`[DEBUG] GB after this upload: ${gbAfterUpload} GB`);
  console.log(`[DEBUG] BP earned per GB: ${process.env.SQ_BP_EARNED_PER_GB}`);

  if (gbAfterUpload >= nextGb) {
    const deltaGb = gbAfterUpload - currentGb;
    const bonusPointsEarned = deltaGb * process.env.SQ_BP_EARNED_PER_GB;
    console.log(
      `[DEBUG] 🎉 Bonus points earned: ${bonusPointsEarned} (${deltaGb} GB × ${process.env.SQ_BP_EARNED_PER_GB})`
    );
    await User.findOneAndUpdate(
      { _id: user._id },
      { $inc: { bonusPoints: bonusPointsEarned } }
    );
  } else {
    console.log(
      `[DEBUG] No bonus points earned yet (need ${formatBytes(
        (nextGb - gbAfterUpload) * BYTES_GB
      )} more)`
    );
  }

  // Update upload progress
  await Progress.findOneAndUpdate(
    { userId: user._id, infoHash },
    {
      $set: {
        userId: user._id,
        infoHash,
        uploaded: {
          session: uploaded,
          total:
            (prevProgressRecord?.uploaded?.total ?? 0) + uploadDeltaSession,
        },
        left: Number(params.left),
      },
    },
    { upsert: true }
  );

  // Update download progress
  const isFreeleech =
    torrent.freeleech || process.env.SQ_SITE_WIDE_FREELEECH === "true";
  console.log(
    `[DEBUG] Freeleech status: ${
      isFreeleech ? "YES (no download counted)" : "NO (download counted)"
    }`
  );

  await Progress.findOneAndUpdate(
    { userId: user._id, infoHash },
    {
      $set: {
        userId: user._id,
        infoHash,
        downloaded: {
          session: isFreeleech
            ? prevProgressRecord?.downloaded?.session ?? 0
            : downloaded,
          total: isFreeleech
            ? prevProgressRecord?.downloaded?.total ?? 0
            : (prevProgressRecord?.downloaded?.total ?? 0) +
              downloadDeltaSession,
        },
        left: Number(params.left),
      },
    },
    { upsert: true }
  );

  // 新增：更新 peer 信息
  console.log("\n---------- PEER UPDATE ----------");

  // 清理过期的 peers
  await cleanExpiredPeers(infoHash);

  // 如果是 stopped 事件，删除 peer 记录
  if (params.event === "stopped") {
    console.log(`[DEBUG] Peer stopped, removing peer record`);
    await Peer.deleteOne({
      infoHash,
      peerId,
      userId: user._id,
    });
  } else {
    // 更新或创建 peer 记录
    const peerData = {
      userId: user._id,
      username: user.username,
      infoHash,
      peerId,
      ip: clientIP, // 现在是纯 IPv4 格式
      port: parseInt(params.port, 10),
      uploaded: (prevProgressRecord?.uploaded?.total ?? 0) + uploadDeltaSession,
      downloaded: isFreeleech
        ? prevProgressRecord?.downloaded?.total ?? 0
        : (prevProgressRecord?.downloaded?.total ?? 0) + downloadDeltaSession,
      left: Number(params.left),
      client: getClientInfo(params.peer_id),
      lastAnnounce: new Date(),
      userAgent: req.headers["user-agent"] || "",
      isSeeder: Number(params.left) === 0,
    };

    await Peer.findOneAndUpdate(
      { infoHash, peerId, userId: user._id },
      { $set: peerData },
      { upsert: true }
    );

    console.log(
      `[DEBUG] ✅ Peer record updated: ${clientIP}:${params.port} (${
        peerData.isSeeder ? "Seeder" : "Leecher"
      })`
    );
  }

  if (params.event === "completed") {
    console.log(
      `[DEBUG] 🎉 Download completed! Incrementing torrent download count.`
    );
    await Torrent.findOneAndUpdate({ infoHash }, { $inc: { downloads: 1 } });
  }

  // 获取种子的统计信息（使用 Peer 表而不是 Progress 表，因为更准确）
  console.log("\n---------- TORRENT PEER STATISTICS ----------");
  const torrentStats = await Peer.aggregate([
    {
      $match: {
        infoHash,
        lastAnnounce: { $gt: new Date(Date.now() - 60 * 60 * 1000) }, // 活跃的 peers
      },
    },
    {
      $group: {
        _id: null,
        totalPeers: { $sum: 1 },
        totalUploaded: { $sum: "$uploaded" },
        totalDownloaded: { $sum: "$downloaded" },
        seeders: { $sum: { $cond: [{ $eq: ["$left", 0] }, 1, 0] } },
        leechers: { $sum: { $cond: [{ $gt: ["$left", 0] }, 1, 0] } },
        activePeers: { $sum: 1 },
      },
    },
  ]);

  const stats = torrentStats[0] || {
    totalPeers: 0,
    seeders: 0,
    leechers: 0,
    totalUploaded: 0,
    totalDownloaded: 0,
    activePeers: 0,
  };

  console.log(`[DEBUG] Active peers: ${stats.activePeers}`);
  console.log(`[DEBUG] Seeders: ${stats.seeders}`);
  console.log(`[DEBUG] Leechers: ${stats.leechers}`);
  console.log(
    `[DEBUG] Total uploaded for this torrent: ${formatBytes(
      stats.totalUploaded
    )}`
  );
  console.log(
    `[DEBUG] Total downloaded for this torrent: ${formatBytes(
      stats.totalDownloaded
    )}`
  );
  console.log(
    `[DEBUG] Health ratio: ${
      stats.seeders > 0
        ? (stats.seeders / (stats.seeders + stats.leechers)).toFixed(2)
        : "0.00"
    }`
  );

  // 新增：获取 peer 列表
  console.log("\n---------- BUILDING PEER LIST ----------");

  const numwant = Math.min(parseInt(params.numwant, 10) || 50, 200); // 限制最大返回数量

  // 获取活跃的 peers，排除自己
  const activePeers = await Peer.find({
    infoHash,
    peerId: { $ne: peerId }, // 不包括自己
    lastAnnounce: { $gt: new Date(Date.now() - 60 * 60 * 1000) }, // 1小时内活跃
  })
    .sort({ lastAnnounce: -1 }) // 按最后 announce 时间排序
    .limit(numwant)
    .lean();

  console.log(
    `[DEBUG] Found ${activePeers.length} active peers (excluding self)`
  );
  console.log(`[DEBUG] Requested numwant: ${numwant}`);

  // 显示 peer 详情
  if (activePeers.length > 0) {
    console.log(`[DEBUG] Returning peers:`);
    activePeers.forEach((peer, index) => {
      console.log(
        `  ${index + 1}. ${peer.username} (${peer.ip}:${peer.port}) - ${
          peer.isSeeder ? "Seeder" : "Leecher"
        } - ${peer.client}`
      );
    });

    // 额外的调试信息
    console.log("\n---------- PEER DATA DEBUG ----------");
    activePeers.forEach((peer, index) => {
      console.log(`[DEBUG] Peer ${index + 1}:`);
      console.log(`  - Username: ${peer.username}`);
      console.log(`  - Original IP: ${peer.ip}`);
      console.log(`  - Port: ${peer.port}`);
      console.log(`  - Is Seeder: ${peer.isSeeder}`);
      console.log(`  - Client: ${peer.client}`);
    });
  } else {
    console.log(`[DEBUG] No active peers to return`);
  }

  // 构建响应
  console.log("\n---------- ANNOUNCE RESPONSE ----------");

  const response = {
    interval: parseInt(process.env.SQ_ANNOUNCE_INTERVAL, 10) || 1800, // 30分钟
    "min interval": parseInt(process.env.SQ_MIN_ANNOUNCE_INTERVAL, 10) || 900, // 15分钟
    complete: stats.seeders,
    incomplete: stats.leechers,
    peers: [], // 将在下面设置
  };

  // 构建 peer 列表
  if (params.compact === "1") {
    // Compact 模式：6字节每个 peer（4字节IP + 2字节端口）
    response.peers = buildCompactPeers(activePeers);
    console.log(
      `[DEBUG] Returning compact peer list: ${activePeers.length} peers, ${response.peers.length} bytes`
    );
  } else {
    // 标准模式：字典列表
    response.peers = buildStandardPeers(activePeers);
    console.log(
      `[DEBUG] Returning standard peer list: ${response.peers.length} peers`
    );
  }

  console.log(`[DEBUG] Response summary:`, {
    interval: response.interval,
    "min interval": response["min interval"],
    complete: response.complete,
    incomplete: response.incomplete,
    "peers count":
      params.compact === "1"
        ? response.peers.length / 6
        : response.peers.length,
  });

  const encodedResponse = bencode.encode(response);
  console.log(`[DEBUG] Response size: ${encodedResponse.length} bytes`);
  console.log(`[DEBUG] ✅ Announce successful!`);
  console.log("========== END OF ANNOUNCE REQUEST ==========\n");

  res.send(encodedResponse);
};

export default handleAnnounce;
